﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartMathLibrary.Space.CoreTypes;

namespace SmartMathLibrary.Space.QueryEngine
{
    /// <summary>
    /// Defines an integral border between option.
    /// </summary>
    public enum IntegralBorderBetweenOption
    {
        /// <summary>
        /// The query will extract all space items inclusive the border values.
        /// </summary>
        InclusiveIntegralBorder = 0,

        /// <summary>
        /// The query will extract all space items exclusive the border values.
        /// </summary>
        ExclusiveIntegralBorder = 1
    }

    /// <summary>
    /// This class represents an integral in border query, which extracts all integrals of a 
    /// specified space where the query value lies between the integral borders a and b.
    /// </summary>
    [Serializable]
    public class IntegralInBorderQuery : AbstractSpaceQuery
    {
        /// <summary>
        /// The compare value.
        /// </summary>
        private double value;

        /// <summary>
        /// The border between option of the query.
        /// </summary>
        private IntegralBorderBetweenOption borderBetweenOption;

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegralInBorderQuery"/> class.
        /// </summary>
        /// <param name="value">The compare value.</param>
        public IntegralInBorderQuery(double value)
            : base()
        {
            this.value = value;
            this.borderBetweenOption = IntegralBorderBetweenOption.InclusiveIntegralBorder;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegralInBorderQuery"/> class.
        /// </summary>
        /// <param name="value">The compare value.</param>
        /// <param name="borderBetweenOption">The border between option of the query.</param>
        public IntegralInBorderQuery(double value, IntegralBorderBetweenOption borderBetweenOption)
            : base()
        {
            this.value = value;
            this.borderBetweenOption = borderBetweenOption;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegralInBorderQuery"/> class.
        /// </summary>
        /// <param name="value">The compare value.</param>
        /// <param name="borderBetweenOption">The border between option of the query.</param>
        /// <param name="status">The object status criteria.</param>
        public IntegralInBorderQuery(double value, IntegralBorderBetweenOption borderBetweenOption,
                                     SpaceObjectStatus status)
            : base(status)
        {
            this.value = value;
            this.borderBetweenOption = borderBetweenOption;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegralInBorderQuery"/> class.
        /// </summary>
        /// <param name="value">The compare value.</param>
        /// <param name="borderBetweenOption">The border between option of the query.</param>
        /// <param name="limit">The maximum number of query results.</param>
        public IntegralInBorderQuery(double value, IntegralBorderBetweenOption borderBetweenOption, int limit)
            : base(limit)
        {
            this.value = value;
            this.borderBetweenOption = borderBetweenOption;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegralInBorderQuery"/> class.
        /// </summary>
        /// <param name="value">The compare value.</param>
        /// <param name="borderBetweenOption">The border between option of the query.</param>
        /// <param name="limit">The maximum number of query results.</param>
        /// <param name="status">The object status criteria.</param>
        public IntegralInBorderQuery(double value, IntegralBorderBetweenOption borderBetweenOption, int limit,
                                     SpaceObjectStatus status)
            : base(limit, status)
        {
            this.value = value;
            this.borderBetweenOption = borderBetweenOption;
        }

        /// <summary>
        /// Gets or sets the compare value.
        /// </summary>
        /// <value>The compare value</value>
        public double Value
        {
            get { return this.value; }
            set { this.value = value; }
        }

        /// <summary>
        /// Gets or sets the border between option of the query.
        /// </summary>
        /// <value>The border between option of the query.</value>
        public IntegralBorderBetweenOption BorderBetweenOption
        {
            get { return this.borderBetweenOption; }
            set { this.borderBetweenOption = value; }
        }

        /// <summary>
        /// Defines the query criteria of the specified query.
        /// </summary>
        /// <param name="item">The query source items.</param>
        /// <returns>
        /// The space ID fulfills the query criteria the method returns true otherwise, false.
        /// </returns>
        public override bool QueryDefinition(ISpaceEntry item)
        {
            if (item is SpaceIntegral)
            {
                SpaceIntegral check = (SpaceIntegral) item;

                if (this.borderBetweenOption == IntegralBorderBetweenOption.ExclusiveIntegralBorder)
                {
                    return ((Math.Min(check.A, check.B) < value) && (value < Math.Max(check.A, check.B)));
                }

                return ((Math.Min(check.A, check.B) <= value) && (value <= Math.Max(check.A, check.B)));
            }

            return false;
        }
    }
}